# include "TextureDrawAble.h"
# include "d3d11.h"
# include "MyDx11.h"
# include "ShaderResourceViewBindAble.h"

TextureDrawAble::TextureDrawAble(MyDx11* _myDx11, int _width, int _height, bool _gpu_copy): m_width(_width), m_height(_height)
{
	this->m_bind_able = new std::vector<BindAbleInterface*>();
	this->changeSize(_myDx11, _width, _height, _gpu_copy);
}

void TextureDrawAble::changeSize(MyDx11* _myDx11, int _width, int _height, bool _gpu_copy)
{
	if (this->m_bind_able->size() != 0) {
		auto resource_view = this->m_bind_able->at(this->m_resource_view_index);
		delete resource_view;
		this->m_bind_able->erase(this->m_bind_able->begin() + this->m_resource_view_index);
	}
	D3D11_TEXTURE2D_DESC tdesc;
	ZeroMemory(&tdesc, sizeof(D3D11_TEXTURE2D_DESC));
	tdesc.Width = this->m_width;
	tdesc.Height = this->m_height;
	tdesc.MipLevels = 1;
	tdesc.ArraySize = 1;
	tdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
	tdesc.SampleDesc.Count = 1;
	tdesc.SampleDesc.Quality = 0;
	tdesc.Usage = _gpu_copy ? D3D11_USAGE_DEFAULT : D3D11_USAGE_DYNAMIC;
	tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
	tdesc.CPUAccessFlags = _gpu_copy ? 0 : D3D11_CPU_ACCESS_WRITE;
	tdesc.MiscFlags = _gpu_copy ? D3D11_RESOURCE_MISC_SHARED : 0;
	this->getDevice(_myDx11)->CreateTexture2D(&tdesc, nullptr, this->m_texture.GetAddressOf());

	CD3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc(D3D11_SRV_DIMENSION_TEXTURE2D);
	this->getDevice(_myDx11)->CreateShaderResourceView(this->m_texture.Get(), &resourceViewDesc, this->m_texture_shader_resource.GetAddressOf());

	Microsoft::WRL::ComPtr<IDXGIResource> sharedTexture = nullptr;
	this->m_texture->QueryInterface(__uuidof(IDXGIResource), (void**)sharedTexture.GetAddressOf());
	sharedTexture->GetSharedHandle(&this->m_shared_handle);

	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = CD3D11_SHADER_RESOURCE_VIEW_DESC(
		this->m_texture.Get(),
		D3D11_SRV_DIMENSION_TEXTURE2D,
		DXGI_FORMAT_B8G8R8A8_UNORM
	);

	this->m_resource_view_index = this->m_bind_able->size();
	this->m_bind_able->push_back(new ShaderResourceViewBindAble(this->getDevice(_myDx11), this->m_texture.Get()));
}

void TextureDrawAble::copyData(ID3D11Device* _device, ID3D11DeviceContext* _context, ID3D11Texture2D* _texture)
{
	if (this->m_shared_handle == nullptr) {
		return;
	}
	Microsoft::WRL::ComPtr<ID3D11Texture2D> texture = nullptr;
	_device->OpenSharedResource(this->m_shared_handle, __uuidof(ID3D11Texture2D), (void**)texture.GetAddressOf());
	if (_texture != nullptr && texture != nullptr) {
		_context->CopyResource(texture.Get(), _texture);
	}
}

void TextureDrawAble::copyData(MyDx11* _myDx11, uint8_t* _buffer, size_t _size)
{
	ID3D11DeviceContext* context = this->getContext(_myDx11);
	context->UpdateSubresource(this->m_texture.Get(), 0, nullptr, _buffer, _size, 0);
}

void TextureDrawAble::draw(MyDx11* _myDx11)
{
	ID3D11DeviceContext* context = this->getContext(_myDx11);
	for (auto item : *this->m_bind_able) {
		item->bind(context);
	}
	context->DrawIndexed(this->m_index_size, 0u, 0u);
}

void TextureDrawAble::insertBindAble(BindAbleInterface* _bind_able)
{
	this->m_bind_able->push_back(_bind_able);
}

TextureDrawAble::~TextureDrawAble()
{
	for (auto item : *this->m_bind_able) {
		delete item;
	}
}

ID3D11Device* TextureDrawAble::getDevice(MyDx11* _myDx11) noexcept
{
	return _myDx11->m_device;
}

ID3D11DeviceContext* TextureDrawAble::getContext(MyDx11* _myDx11) noexcept
{
	return _myDx11->m_context;
}
